#!/usr/bin/python
# -*- coding: utf-8 -*-
import httplib, mimetypes, urllib2, cookielib, simplejson
from urllib import urlencode

def encode_multipart_formdata(fields, files):
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    """
    def get_content_type(filename):
        return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
    
    #BOUNDARY = mimetools.choose_boundary()
    BOUNDARY = '-----------------------------7441951230145'
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body


# serverside implement of qzone login md5 algorithm
from hashlib import md5

def _qqmd5_3times(pstr):
    # md5 for 3 times
    # notice that the first two digests MUST NOT return hex characters 
    m = md5(); m.update(pstr)
    b1 = m.digest()
    m = md5(); m.update(b1)
    b2 = m.digest()
    m = md5(); m.update(b2)
    b3 = m.hexdigest()
    return b3.upper()

def _qqmd5_1time(pstr):
    m = md5(); m.update(pstr)
    return m.hexdigest().upper()

def qqmd5_pw(pstr, vcode):
    return _qqmd5_1time(_qqmd5_3times(pstr) + vcode.upper())

# choose a album


#httplib.HTTPConnection.debuglevel = 1
agent = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009030422 Ubuntu/8.04 (hardy) Firefox/3.0.7'
cj     = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
#urllib2.install_opener(opener) # so urlopen() uses the openner

# add basic headers to simulate as a browser
opener.addheaders=[('Accept', '*/*'),
                  ('Accept-Charset', 'GB2312,utf-8;q=0.7,*;q=0.7'),
                  ('Accept-Encoding', 'deflate'), # DO NOT ACCEPT gzip
                  ('Accept-Language', 'zh-cn,zh;q=0.5'),
                  ('User-agent', agent),]


def send_qzone_imgs(qqid, password, imgs, names, alix=0):
    # login with qq numbers, login with email account would fail
    # send_qzone_imgs(qqid, password, ['im1.jpg', 'im2.jpg', ...], ['name1', 'name2', ...], alix = 0)
    import random
    global opener
    global cj
    random.seed()
    
    # 1. login to qzone
    req = urllib2.Request('http://qzone.qq.com')
    ret = opener.open(req)
    # client side set cookie 'pvid'
    pvid = int((random.random()*2147483647)*random.random()*10000)%10000000000
    ret.headers['Set-Cookie'] = "pvid=%d; PATH=/; DOMAIN=qq.com;" % pvid
    cj.extract_cookies(ret, req)
 
    r = random.random() # r in (0, 1), post to generate a verifycode
    # request to get verify code
    ret = opener.open('http://ptlogin2.qq.com/check?uin=%s&appid=15000101&r=%f' % (qqid, r))
    vc = ret.read()[18:22] # read() should be like 'ptui_checkVC('0','!6R1');'
    # login, go around to get cookies
    ret = opener.open('http://ptlogin2.qq.com/login?u=%s&p=%s&verifycode=%s'%(qqid, qqmd5_pw(password, vc), vc)+'&aid=15000101&u1=http%3A%2F%2Fimgcache.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&h=1&ptredirect=1&ptlang=2052&from_ui=1&dumy=&fp=loginerroralert') 
    ret = opener.open('http://imgcache.qq.com/qzone/v5/loginsucc.html?para=izone')
    
    if qqid.find('@'): # is email address, then get the qq number of it and save it to qqid
        for c in cj:
            if c.name == 'uin':
                qqid = int(c.value[1:])
                print qqid
        
    ret = opener.open('http://user.qzone.qq.com/%s' % qqid)
    
    # 2. get albums list (pingfore.qq.com ignored)
    ret = opener.open('http://xalist.photo.qq.com/fcgi-bin/fcg_list_album?uin=%s&outstyle=2&t=%f' % (qqid, random.random()))
    alobj = simplejson.loads(ret.read()[11:-4].decode('gb2312')) # loads album list from a json string in gb2312
    
    
    albumcnt = alobj['left']['album']['albumnum']
    # create a album when there's no one
    if albumcnt == 0:
        print 'create default album'
        ret = opener.open('http://xa.photo.qq.com/cgi-bin/common/cgi_add_album', 
                          urlencode({ 
                           'albumname'  : str('default'),
                           'albumdesc'  : '',
                           'albumclass' : 100,
                           'priv'       : 1,
                           'question'   : 1,
                           'answer'     : 1,
                           'bitmap'     : 10000000,
                           'output_type' : 'jsonhtml',
                           'refer'      : 'qzone',
                           'uin'        : qqid, 
                           }))
        # get alobj again
        ret = opener.open('http://xalist.photo.qq.com/fcgi-bin/fcg_list_album?uin=%s&outstyle=2&t=%f' % (qqid, random.random()))
        alobj = simplejson.loads(ret.read()[11:-4].decode('gb2312')) # loads album list from a json string in gb2312
        alix = 0 # choose the first album
    elif albumcnt <= alix:
        print 'illegal album index, post to first album'
        alix = 0
    
    #albumlist = [{'name' : x['name'], 'id' : x['id'], } for x in albums['album']]
    al = alobj['album'][alix]
    leftal = alobj['left']['album']
    
    
    # 3. encode image and upload
    fields = [
        ('total',     str(al['total'])),
        ('albumid',   str(al['id'])),
        ('diskused',  str(leftal['diskused'])),
        ('tagtext', ''),
        ('refer', 'qzone'),
        ('charset', 'utf-8'),
        ('output_charset', 'utf-8'),
        ('bgid', ''),
        ('tpid',''),
        ('route', '1'),
        ('domain', ''),
        ('albumname', al['name'].encode('utf8')),
        ('albumdesc', al['desc'].encode('utf8')),
        ('comment',   str(al['comment'])),
        ('albumclass',str(al['classid'])),
        ('albumpriv', str(al['priv'])),
        ('albumhandset', str(al['handset'])),
        ('albumbitmap',  str(al['bitmap'])),
    ]
    
    
    cookiestr = ''.join([c.name+'='+c.value+'; ' for c in cj if c.name in [
                    'pt2gguin', 'ptcz', 'pvid', 'skey', 'uin']])
    # add new cookies in upload POST
    cookiestr += 'albumclass=%d; albumhandset=%d; albumname=%s; albumpriv=%d;pt2'\
                    % (al['classid'], al['handset'], al['name'].encode('utf8'), al['priv'])
    
    for ix in range(len(imgs)):
        print ix
        f = open(imgs[ix], 'rb')
        files = [('filename', names[ix], f.read())]
        f.close()
        #for im in imgs:
        #    f = open(im, 'rb')
        #    files.append(('filename', im, f.read()))
        #    f.close()
            
       
        
        contenttype, body = encode_multipart_formdata(fields, files)
        h = httplib.HTTPConnection('xaup.photo.qq.com')
        headers = {
            'User-Agent'   : agent,
            'Content-Type' : contenttype,
            'Cookie'       : cookiestr,
            'Referer'      : 'http://ctc.qzs.qq.com/qzone/client/photo/pages/qzone_v4/upload_web.htm',
            'Accept'       : '*/*',
            'Accept-Language': 'zh-cn,zh;q=0.5',
            'Accept-Encoding': 'deflate',
            'Accept-Charset' : 'GB2312,utf-8;q=0.7,*;q=0.7',
            'Keep-Alive': '115',
            'Connection': 'keep-alive',
        }
        print 'posting'
        h.request('POST', '/cgi-bin/upload/cgi_upload_pic ', body, headers)
        res = h.getresponse()
        
        # print upload response
        print res.read().decode('utf8', 'ignore')
    
    return  
    
if __name__ == '__main__':
    send_qzone_imgs('jagt@live.com', '111111111', ['test.png' for x in range(350)], ['pt%d' % x for x in range(350)], 10)
    #while(1):
    #    send_qzone_imgs(1370885733, '111111111', ['test.png'], ['pt1'   ], 10)
    
    